/**
 * Project Name:BasePagingRepositoryImpl.java
 * File Name:BasePagingRepositoryImpl.java
 * Date:2019/4/6 17:59
 * Copyright (c) 2019, zhang.xiangyu@foxmail.com All Rights Reserved.
 */
package com.meatball.base.repository.impl;

import com.meatball.base.repository.BasePagingRepository;
import com.meatball.base.repository.matcher.MeatballExample;
import com.meatball.base.repository.matcher.MeatballMatcher;
import com.meatball.constant.MeatballConst;
import com.meatball.utils.response.ResultPageMsg;
import com.mongodb.QueryBuilder;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang.ArrayUtils;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.lang.reflect.Field;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;

/**
 * @Title: BasePagingRepositoryImpl.java
 * @Description: todo(自定义查询实现)
 * @Author: 張翔宇
 * @Date: 2019/4/6 17:59
 * @Version: V1.0
 */
@Log4j2
@Repository
public class BasePagingRepositoryImpl<T> implements BasePagingRepository<T> {

    private final MongoTemplate mongoTemplate;

    public BasePagingRepositoryImpl (MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    @Override
    public Mono<T> findPage(MeatballExample<T> example, Pageable pageable) {
        Query query = this.formatQuery(example);
        query.with(PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), pageable.getSort()));
        long totalCount = mongoTemplate.count(query, example.getProbeType());
        List<T> list = mongoTemplate.find(query, example.getProbeType());
        return (Mono<T>) Mono.just(new ResultPageMsg(MeatballConst.ResultCode.SUCCESS.CODE,
                MeatballConst.ResultCode.SUCCESS.MESSAGE,totalCount, list));
    }


    @Override
    public Flux<T> findList(MeatballExample<T> example, Sort sort) {
        // 格式化参数
        Class<T> entityClass = (Class<T>) example.getProbe().getClass();
        Query query = this.formatQuery(example);
        query.with(sort);
        return (Flux<T>) Flux.just(mongoTemplate.find(query, entityClass));
    }

    /**
     * @title: params
     * @description: todo(格式化请求参数)
     * @params: [t]
     * @return: com.meatball.base.repository.domain.Params    返回类型
     * @author: 張翔宇
     * @date: 2019/4/4 22:26
     */
    private static <T> Query formatQuery (MeatballExample<T> example) {
        MeatballMatcher.PropertySpecifiers specifiers =  example.getMatcher().getPropertySpecifiers();
        QueryBuilder queryBuilder = new QueryBuilder();
        T t = example.getProbe();
        Class<?> tClass = example.getProbeType();
        Field[] field = (Field[]) ArrayUtils.addAll(tClass.getDeclaredFields(), tClass.getSuperclass().getDeclaredFields());
        bgm: for (Field info : field) {
            info.setAccessible(true);
            try {
                String methodName = info.getName();
                Object methodValue = info.get(t);
                for (MeatballMatcher.PropertySpecifier specifier : specifiers.getSpecifiers()) {

                    if (specifier.getPath().equals(info.getName())) {
                        // 包含
                        if (specifier.getStringMatcher().equals(MeatballMatcher.StringMatcher.CONTAINING) && methodValue != null) {
                            Pattern pattern=Pattern.compile("^.*" + methodValue + ".*$", Pattern.CASE_INSENSITIVE);
                            queryBuilder.and(info.getName()).regex(pattern);
                            continue bgm;
                        }
                        // 区间
                        if (specifier.getStringMatcher().equals(MeatballMatcher.StringMatcher.BETWEEN)) {
                            Date start = specifier.getStart();
                            Date end = specifier.getEnd();
                            // 大于等于
                            queryBuilder.and(methodName).greaterThanEquals(start);
                            // 小于等于
                            queryBuilder.and(methodName).lessThanEquals(end);
                            continue bgm;
                        }
                        // in
                        if (specifier.getStringMatcher().equals(MeatballMatcher.StringMatcher.IN)) {
                            queryBuilder.and(methodName).in(specifier.getParameter());
                        }
                    }
                }
                if (methodValue != null) {
                    queryBuilder.and(methodName).is(methodValue);
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return new BasicQuery(queryBuilder.get().toString());
    }
}
